package com.tlw.practice.tlw.utils;
import com.tlw.practice.tlw.annotation.annotations;
import com.tlw.practice.tlw.entity.AuditEntity;
import com.tlw.practice.tlw.entity.LeaveEntity;
import com.tlw.practice.tlw.service.AuditService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 对象修改对比
 * @param <T>
 */
@Component //申明为spring组件
public class BeanChangeUtil<T> {
    // 创建留痕实例
    AuditEntity audit = new AuditEntity();

    @Autowired
    private  AuditService auditService;
    private static BeanChangeUtil beanChangeUtil;    //  关键点1   静态初使化 一个工具类  这样是为了在spring初使化之前

    @PostConstruct     //关键二   通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
    public void init() {
        beanChangeUtil = this;
        beanChangeUtil.auditService = this.auditService;   // 初使化时将已静态化的testService实例化
    }

    public String contrastObj(Object oldBean, Object newBean) {
        // 创建字符串拼接对象
        StringBuilder str = new StringBuilder();
        // 转换为传入的泛型T
        T pojo1 = (T) oldBean;
        T pojo2 = (T) newBean;
        // 通过反射获取类的Class对象
        Class clazz = pojo1.getClass();
        // 获取类型及字段属性
        Field[] fields = clazz.getDeclaredFields();
        return jdk8BeforeStr(fields, pojo1, pojo2, str,clazz);
//        return jdk8OrAfter(fields, pojo1, pojo2, str,clazz);
    }

//    public AuditEntity contrastAudit(LeaveForm oldLeave, LeaveForm newLeave) {
//        // 填充留痕数据
//        audit.setObjectId(oldLeave.getId());
//        // 创建字符串拼接对象
//        StringBuilder str = new StringBuilder();
//        // 转换为传入的泛型T
//        T pojo1 = (T) oldLeave;
//        T pojo2 = (T) newLeave;
//        // 通过反射获取类的Class对象
//        Class clazz = pojo1.getClass();
//        // 获取类型及字段属性
//        Field[] fields = clazz.getDeclaredFields();
//        return jdk8BeforeAudit(fields, pojo1, pojo2, str,clazz);
////        return jdk8OrAfter(fields, pojo1, pojo2, str,clazz);
//    }

    public AuditEntity recordChange( LeaveEntity leave) {
        // 填充留痕数据
        audit.setObjectId(leave.getId());
        // 创建字符串拼接对象
        StringBuilder str = new StringBuilder();
        // 转换为传入的泛型T
        T pojo = (T) leave;

        // 通过反射获取类的Class对象
        Class clazz = pojo.getClass();
        // 获取类型及字段属性
        Field[] fields = clazz.getDeclaredFields();
        return jdk8BeforeAudit(fields, pojo, str,clazz);
//        return jdk8OrAfter(fields, pojo1, pojo2, str,clazz);
    }

    // jdk8 普通循环方式 - 返回audit
    public AuditEntity jdk8BeforeAudit(Field[] fields,T pojo,StringBuilder str,Class clazz){
        int i = 1;
        try {
            for (Field field : fields) {
                if(field.isAnnotationPresent(annotations.PropertyMsg.class)){
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                    // 获取对应属性值
                    Method getMethod = pd.getReadMethod();
                    Object o1 = getMethod.invoke(pojo);
                    if (o1 == null ) {
                        continue;
                    }
                    // 如果修改字段是时间，格式化
                    if (o1 instanceof Date){
                        // 时间格式化
                        SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS" );
                        o1 = sdf.format(o1);
                    }
                        // 输出字符串
                        str.append(i + "、" + field.getAnnotation(annotations.PropertyMsg.class).value() + ":" + ",修改为=>" + o1 + "\n");
                        // 记录留痕数据 - 字段、新旧值
                        audit.setFieldName(field.getAnnotation(annotations.PropertyMsg.class).value());
                        audit.setFieldValue(o1.toString());
                        List<AuditEntity> result = beanChangeUtil.auditService.findOneByLeaveId(audit.getObjectId());
                        if (result.size()>0){
                            // 不为空，说明这个属性已经有记录了 - 版本+1
                            audit.setVersion(result.get(0).getVersion()+1);
                            audit.setEventId(UUID.randomUUID().toString());
                        } else {
                            // 为空，没有记录，版本号从1开始
                            audit.setVersion(1);
                            audit.setEventId(UUID.randomUUID().toString());
                        }
                        // 记录修改到数据库
//                        System.err.println("审计数据："+audit);
//                        auditService.saveAudit(audit);
                        i++;
//                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
//        return str.toString();
        return audit;
    }

    // jdk8 普通循环方式 - 返回字符串
    public String jdk8BeforeStr(Field[] fields,T pojo1,T pojo2,StringBuilder str,Class clazz){
        int i = 1;
        try {
            for (Field field : fields) {
                if(field.isAnnotationPresent(annotations.PropertyMsg.class)){
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                    // 获取对应属性值
                    Method getMethod = pd.getReadMethod();
                    Object o1 = getMethod.invoke(pojo1);
                    Object o2 = getMethod.invoke(pojo2);
//                    System.out.println(o1 == o2);
                    if (o1 == null || o2 == null) {
                        continue;
                    }
                    if (!o1.toString().equals(o2.toString())) {
                    // 如果修改字段是时间，格式化
                    if (o1 instanceof Date){
                        // 时间格式化
                        SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS" );
                        o1 = sdf.format(o1);
                        o2 = sdf.format(o2);
                    }
                    // 输出字符串
                    str.append(i + "、" + field.getAnnotation(annotations.PropertyMsg.class).value() + ":" + "修改前=>" + o1 + ",修改后=>" + o2 + "\n");
                    // 记录留痕数据 - 字段、新旧值
                    audit.setEventId(UUID.randomUUID().toString());
                    audit.setFieldName(field.getAnnotation(annotations.PropertyMsg.class).value());
                    audit.setFieldValue(o1.toString());
//                        AuditEntity result = auditService.findOneByLeaveId("5");
//                        if (result != null){
//                            // 不为空，说明这个属性已经有记录了 - 版本+1
//                            audit.setVersion(result.version+1);
//                        } else {
//                            // 为空，没有记录，版本号从1开始
//                            audit.setVersion(1);
//                        }
                    // 记录修改到数据库
//                        System.err.println("审计数据："+audit);
//                        auditService.saveAudit(audit);
                    i++;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str.toString();
    }

    // lambda表达式，表达式内部的变量都是final修饰，需要传入需要传入final类型的数组
    public String jdk8OrAfter(Field[] fields, T pojo1, T pojo2, StringBuilder str, Class clazz){
        final int[] i = {1};
        Arrays.asList(fields).forEach(f -> {
            if(f.isAnnotationPresent(annotations.PropertyMsg.class)){
                try {
                    PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz);
                    // 获取对应属性值
                    Method getMethod = pd.getReadMethod();
                    Object o1 = getMethod.invoke(pojo1);
                    Object o2 = getMethod.invoke(pojo2);
                    if (o1 == null || o2 == null) {
                        return;
                    }
                    if (!o1.toString().equals(o2.toString())) {
                        str.append(i[0] + "、" + f.getAnnotation(annotations.PropertyMsg.class).value() + ":" + "修改前=>" + o1 + "\t修改后=>" + o2 + "\n");
                        i[0]++;
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
        return str.toString();
    }
}